import pathlib
import time
import re
import typing
import os
import rich.traceback
import yaml
import ctypes
import psutil
import subprocess
import requests
import winsound
import datetime
import rich
import enum
from selenium.webdriver.edge.webdriver import WebDriver
from selenium.webdriver.edge.service import Service
from selenium.webdriver.edge.options import Options
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.common.exceptions import *





def Custom_Message(parent_hwnd: int = 0, title: str = 'default_title', text: str = 'default_text', type: int = 0) -> int:
    """
    显示自定义消息框。

    该函数通过 ctypes 调用 Windows API 来显示一个带有自定义内容和标题的消息框。
    可以用于快速在 Windows 应用程序中创建消息提示。

    Args:
        parent_hwnd (int): 父窗口的窗口句柄。默认值为 0，表示没有父窗口。
        title (str): 消息框的标题。默认值为 'default_title'。
        text (str): 消息框的内容。默认值为 'default_text'。
        type (int): 消息框的类型，决定了消息框的样式和按钮。默认值为 0。

    Returns:
        int: 用户点击消息框按钮后返回的值，表示用户的选择。
    """
    return ctypes.windll.user32.MessageBoxW(parent_hwnd, text, title, type)




def Checkout_Has_Msedge_Process(_process_name:str="msedge.exe"):
    """检查是否存在指定名称的进程
        
        Args:
            _process_name (str): 进程名称
        
        Returns:
            bool: 如果存在指定名称的进程，则返回 True，否则返回 False
        
        Example:
            >>> CheckMsEdgeProcess('msedge.exe')
            True
        """
    _is_process_running = False
    for _proc in psutil.process_iter(['name']):
        if _proc.info['name'] == _process_name:
            _is_process_running = True
            break
    return _is_process_running




def Checkout_Debug_Mode_Activate(local:str="127.0.0.1",port:str="9652") -> bool:
    """
    检查调试模式路径是否可用

    Returns:
        bool: 如果调试模式路径可用，则返回 True，否则返回 False

    Example:
        >>> MyEdge.CheckOutDebugModePath()
        True
    """
    url = f"http://{local}:{port}/json/version"
    try:
        response = requests.get(url=url)
        if response.status_code == 200:
            result = True
        else:
            result = False
    except Exception as e:
        print(f"请求调试模式路径时发生错误: {e}")
        result = False
    return result




def Close_All_Msedge_Process(_process_name: str="msedge.exe") -> bool:
    """
    关闭所有指定名称的进程

    Args:
        _process_name (str): 进程名称

    Returns:
        bool: 如果成功关闭所有指定名称的进程，则返回 True，否则返回 False

    Example:
        >>> MyEdge.CloseAllMsEdgeProcess('msedge.exe')
        True
    """
    success = True  # 初始化返回值
    for proc in psutil.process_iter(['pid', 'name']):
        if _process_name == proc.info['name']:
            try:
                proc.kill()  # 关闭进程
                print(f"Closed Microsoft Edge process with PID: {proc.info['pid']}")
            except Exception as e:
                print(f"Failed to close Microsoft Edge process with PID: {proc.info['pid']}. Error: {e}")
                success = False  # 如果关闭失败，设置返回值为 False
    return success




def Start_Debugmode_Browser(local:str="127.0.0.1",debugport:int=9652,user_data_dir:str=None):
    # 定义启动命令
    # command = r'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port=9652 --disable-extensions "http://127.0.0.1:9652/json/version" "https://fxg.jinritemai.com/ffa/mshop/homepage/index" "https://myseller.taobao.com/home.htm/QnworkbenchHome/"'
    if user_data_dir:
        command = rf'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port={debugport} --user-data-dir="{user_data_dir}" "http://{local}:{debugport}/json/version"'
    else:
        command = rf'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port={debugport} "http://{local}:{debugport}/json/version"'
    
    # 启动新的进程
    CREATE_NEW_CONSOLE = 0x00000010
    subprocess.Popen(command, shell=True, creationflags=CREATE_NEW_CONSOLE)




def Start_Debugmode_Browser_With_Extensions(local:str="127.0.0.1",debugport:int=9652,user_data_dir:str=None):
    # 定义启动命令
    # command = r'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port=9652 "http://127.0.0.1:9652/json/version" "https://fxg.jinritemai.com/ffa/mshop/homepage/index" "https://myseller.taobao.com/home.htm/QnworkbenchHome/"'
    if user_data_dir:
        command = rf'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port={debugport} --user-data-dir="{user_data_dir}" "http://{local}:{debugport}/json/version"'
    else:
        command = rf'"C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" --remote-debugging-port={debugport} "http://{local}:{debugport}/json/version"'
    
    # 启动新的进程
    CREATE_NEW_CONSOLE = 0x00000010
    subprocess.Popen(command, shell=True, creationflags=CREATE_NEW_CONSOLE)




def Fast_Create_WebDriver_Wait_Action(local:str="127.0.0.1",port:int=9652) -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
    """快速创建 WebDriver、WebDriverWait 和 ActionChains 实例。

    Returns:
        typing.Tuple[WebDriver, WebDriverWait, ActionChains]: 返回 WebDriver、WebDriverWait 和 ActionChains 实例的元组。
    """
    options = Options()
    options.add_experimental_option("debuggerAddress", f"{local}:{port}")
    service = Service()
    driver = WebDriver(options=options, service=service)
    wait = WebDriverWait(driver=driver,timeout=10)
    actions = ActionChains(driver=driver)
    return driver,wait,actions




def Fast_Link_Debugmode_Browser(local:str="127.0.0.1",debugport:int=9652,user_data_dir:str=None) -> typing.Tuple[WebDriver, WebDriverWait, ActionChains]:
    CheckResul_Process = Checkout_Has_Msedge_Process()  # 检测是否有 msedge.exe 进程    
    if(CheckResul_Process == False):
        Start_Debugmode_Browser(debugport=debugport,user_data_dir=user_data_dir)
    else:
        CheckResul_DebugModu = Checkout_Debug_Mode_Activate(local=local,port=debugport)
        if(CheckResul_DebugModu == False and user_data_dir is not None):
            Start_Debugmode_Browser(debugport=debugport,user_data_dir=user_data_dir)
            return Fast_Create_WebDriver_Wait_Action(local=local,port=debugport)
        elif(CheckResul_DebugModu == False and user_data_dir is None):
            _select_execute = Custom_Message(parent_hwnd=0,title="提示",text="检测到有 msedge.exe 进程，但未启用调试模式，是否关闭所有的浏览器进程!")
            match _select_execute:
                case 1:
                    Close_All_Msedge_Process()
                    Start_Debugmode_Browser()
                case 2:
                    exit(0)
                case _:
                    exit(0)
        else:
            return Fast_Create_WebDriver_Wait_Action(local=local,port=debugport)


def Goto_CurrentActivateUrl(driver: WebDriver) -> None:
    """使用 requests 获取当前激活的页面的 url,并切换到当前激活的页面.

    Args:
        driver (WebDriver): WebDriver 实例

    Returns:
        _type_: None
    """
    debug_json_data = requests.get(
        url="http://127.0.0.1:9652/json", timeout=5).json()

    # 判断获取回来的数据是否正确
    if not isinstance(debug_json_data, list):
        print("接口返回数据格式不正确（非列表或为空）")
        return None

    # 过来掉不需要的 page 页面
    filter_json_data = list(
                                    filter(lambda item: (
                                        item['type'] == "page" and
                                        not item['title'].lower().startswith("devtools") and
                                        not item['title'].lower().startswith("offscreen") and
                                        not item['title'].lower().startswith("新标签页") and
                                        not item['url'].lower().startswith("edge://newtab/") and
                                        not item['url'].lower().startswith("chrome-extension") and
                                        not item['url'].lower().startswith("chrome-devtools")
                                    ), debug_json_data)
                                )
    current_activate_handle = filter_json_data[0]['id']
    driver.switch_to.window(current_activate_handle)
            




def _Find_input_element(driver:WebDriver,wait:WebDriverWait,actions:ActionChains,label:str) -> WebElement:
    anchor_element = driver.find_elements(by=By.XPATH,value=f"//*[(self::span or self::label or self::div) and text()='{label}']")
    if len(anchor_element) == 1:
        find_xpath_path = "./parent::*//input"
        while True:
            try:
                element = anchor_element[0].find_element(by=By.XPATH,value=find_xpath_path)
                return element
            except NoSuchElementException:
                print(f"提示 : 当前层级没有找到 Input 元素,继续向上查找!")
                find_xpath_path = find_xpath_path.replace("//input","/parent::*//input")
                continue
            




def _Find_ByType_input_element(driver:WebDriver,wait:WebDriverWait,actions:ActionChains,label:str,InputType:typing.Literal["","text","file"]="text",InputAccept:typing.Literal['',"video","mp4","image"]="",Multiple:bool=False,max_attempts:int = 5) -> WebElement:
    """该函数用于查找输入元素。
    """
    # 锚点元素必须是全局唯一的
    print(f"//*[(self::span or self::label or self::div) and text()='{label}']")
    elements = driver.find_elements(by=By.XPATH,value=f"//*[(self::span or self::label or self::div) and text()='{label}']")

    if elements.__len__() == 1:
        anchor_element = elements[0]
        find_xpath_path = f"./parent::*"
        input_xpath = "input"
        
        if InputType != "":
            input_xpath += f"[@type='{InputType}']"
        if InputAccept != "":
            input_xpath += f"[contains(@accept,'{InputAccept}')]"
        if Multiple == True:
            input_xpath += f"[@multiple]"
        
        find_xpath_path = f"./parent::*//{input_xpath}"

        attempt = 0
        while True:
            try:
                print(f"提示 : ./parent::*//{input_xpath}")
                element = anchor_element.find_element(by=By.XPATH,value=find_xpath_path)
                return element
            except NoSuchElementException:
                # print(f"提示 : 当前层级没有找到 Input 元素,继续向上查找!")
                # find_xpath_path = find_xpath_path.replace(f"//{input_xpath}",f"/parent::*//{input_xpath}")
                attempt += 1
                anchor_element = anchor_element.find_element(by=By.XPATH,value="./parent::*")
                
                if attempt >= max_attempts:
                    print(f"提示 : 尝试次数已达到最大值,退出查找!")
                    break
                else:
                    continue
    else:
        print(f"提示 : 锚点元素必须是全局唯一的!当前锚点元素个数 : {elements.__len__()}")

# 定义条件类型的枚举
class ConditionType(enum.Enum):
    """
    定义元素验证条件的枚举类型
    
    包含输入框值验证和文本值验证两大类条件
    """
    InputValueIsNull = 1          # 输入框值为空
    InputValueIsNotNull = 2       # 输入框值不为空
    InputValueEqual = 3           # 输入框值等于指定值
    InputValueNotEqual = 4        # 输入框值不等于指定值
    InputValueInclude = 5         # 输入框值包含指定内容
    InputValueNotInclude = 6      # 输入框值不包含指定内容
    
    TextValueIsNull = 7           # 文本内容为空
    TextValueIsNotNull = 8        # 文本内容不为空
    TextValueEqual = 9            # 文本内容等于指定值
    TextValueNotEqual = 10        # 文本内容不等于指定值
    TextValueInclude = 11         # 文本内容包含指定内容
    TextValueNotInclude = 12      # 文本内容不包含指定内容

def CustomFindElement(
    driver: WebDriver,
    target_xpath: str,
    step_name: str = "未命名步骤",
    precondition_xpath: str = None,
    precondition_type: ConditionType = None,
    precondition_value: str = None,
    postcondition_xpath: str = None,
    postcondition_type: ConditionType = None,
    postcondition_value: str = None,
    timeout: int = 10,
    retry_count: int = 0,
    loop_interval: float = 0.1,
    terminate_on_failure: bool = False
) -> WebElement:
    """
    执行带前置条件和后置条件验证的元素查找操作，支持自定义条件验证。
    
    该函数会在查找目标元素前后分别验证前置条件和后置条件，确保操作环境符合预期。
    支持重试机制，在超时范围内持续尝试查找元素和验证条件。
    
    Args:
        driver (WebDriver): Selenium WebDriver实例
        target_xpath (str): 目标元素的XPath表达式
        step_name (str, optional): 步骤名称，用于日志记录
        precondition_xpath (str, optional): 前置条件元素的XPath，None表示跳过验证
        precondition_type (ConditionType, optional): 前置条件类型
        precondition_value (str, optional): 前置条件所需的值（如属性值、文本值）
        postcondition_xpath (str, optional): 后置条件元素的XPath，None表示跳过验证
        postcondition_type (ConditionType, optional): 后置条件类型
        postcondition_value (str, optional): 后置条件所需的值（如属性值、文本值）
        timeout (int, optional): 单次验证的超时时间（秒）
        retry_count (int, optional): 重试次数
        loop_interval (float, optional): 重试间隔（秒）
        terminate_on_failure (bool, optional): 验证失败时是否终止程序
        
    Returns:
        WebElement: 操作成功返回目标元素，失败返回None
        
    Raises:
        None: 函数内部处理所有异常，不主动抛出
        
    Notes:
        - 当terminate_on_failure为True时，前置条件或后置条件失败会导致程序退出
        - 验证条件支持输入框值和文本内容的多种比较方式
        - 超时机制基于datetime计算，避免使用time.sleep造成的固定等待
    """
    
    attempt = 0         # 当前重试次数
    max_attempts = retry_count + 1      # 最大重试次数
    

    # 开始查找
    while attempt < max_attempts:   
        attempt += 1
        rich.print(f"[red bold]\n提示 : 当前执行 [{step_name}] 步骤，尝试次数 {attempt}/{max_attempts}")

        element : WebElement = None

        # 前置条件验证
        # print(f"\t提示 : 开始验证 [{step_name}] 前置条件 [{precondition_xpath}] ...")
        rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 前置条件 [{precondition_xpath}] ...")
        preconditions_result : bool = False
        if precondition_xpath == None or precondition_xpath == "":
            rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 前置条件验证为空,当前前置条件已满足!")
            preconditions_result = True
        else:
            rich.print(f"[green bold]\t提示 : 正在验证 [{step_name}] 前置条件验证不为空,开始进行验证 ... ")
            preconditions_verify_start_time = datetime.datetime.now()
            while preconditions_verify_start_time + datetime.timedelta(seconds=timeout) > datetime.datetime.now():
                try:
                    precondition_element = driver.find_element(by=By.XPATH,value=precondition_xpath)
                    
                    # 判断是那种验证类型
                    if precondition_type is None or precondition_type == "" or precondition_type == "":
                        preconditions_result = True
                        break
                    
                    # ConditionType.InputValueIsNull
                    elif precondition_type == ConditionType.InputValueIsNull:                        
                        if precondition_element.get_attribute("value") == "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.InputValueIsNotNull
                    elif precondition_type == ConditionType.InputValueIsNotNull:
                        if precondition_element.get_attribute("value") != "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.InputValueEqual
                    elif precondition_type == ConditionType.InputValueEqual:
                        if precondition_element.get_attribute("value") == precondition_value:
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.TextValueIsNull
                    elif precondition_type == ConditionType.TextValueIsNull:
                        if precondition_element.text == "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.TextValueIsNotNull
                    elif precondition_type == ConditionType.TextValueIsNotNull:
                        if precondition_element.text != "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.TextValueEqual
                    elif precondition_type == ConditionType.TextValueEqual:
                        if precondition_element.text == precondition_value:
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    else:
                        rich.print(f"[green bold]\t提示 : 没有匹配到条件类型!")
                    
                    
                except Exception as e:
                    preconditions_result = False
                finally:
                    time.sleep(loop_interval)
                
        
        # 判断前置条件是否满足
        if preconditions_result == False:    
            if terminate_on_failure == True:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 前置条件未满足，程序已终止执行！\n")
                exit(0)
            else:
                rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 前置条件未满足，程序进入下一次尝试！\n")
                continue
        else:
            rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 前置条件已满足，目标元素: {target_xpath}\n")


        # 查找目标元素
        rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 目标元素: {target_xpath} ...")
        if target_xpath == None or target_xpath == "":
            rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 目标元素为空,当前函数运行结束!")
            return None
        else:
            rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 正在查找目标元素: {target_xpath}")
            target_element_startfind_time = datetime.datetime.now()
            while target_element_startfind_time + datetime.timedelta(seconds=timeout) > datetime.datetime.now():
                try:
                    element = driver.find_element(By.XPATH, target_xpath)
                    # rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 找到目标元素: {target_xpath}")
                    # rich.print(f"[green bold]\t提示 : 目标元素 [{target_element}]\n")
                    break
                except:
                    # 找不到【目标元素】，不做任何的处理，直接进入下一次的循环。
                    time.sleep(loop_interval)
                    continue
                    

        if element:
            rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 目标条件已满足，目标元素路径: {target_xpath}")
            rich.print(f"[yellow bold]\t提示 : 目标元素 [{element}]\n")
        else:
            rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 未找到目标元素: {target_xpath}，程序进入下一次尝试！\n")
            continue

        

        # 后置条件验证
        rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 后置条件 [{postcondition_xpath}] ...")
        postcondition_result : bool = None
        if postcondition_xpath == None or postcondition_xpath == "":
            rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 后置条件验证为空,当前后置条件已满足!")
            postcondition_result = True
        else:
            rich.print(f"[green bold]\t提示 : 正在验证 [{step_name}] 后置条件验证不为空,开始进行验证 ... ")
            preconditions_verify_start_time = datetime.datetime.now()
            while preconditions_verify_start_time + datetime.timedelta(seconds=timeout) > datetime.datetime.now():
                try:
                    postcondition_element = driver.find_element(by=By.XPATH,value=postcondition_xpath)
                    
                    # 判断是那种验证类型
                    if postcondition_type is None or postcondition_type == "" or postcondition_type == "":
                        postcondition_result = True
                        break
                    
                    # ConditionType.InputValueIsNull
                    elif postcondition_type == ConditionType.InputValueIsNull:
                        if postcondition_element.get_attribute("value") == "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.InputValueIsNotNull
                    elif postcondition_type == ConditionType.InputValueIsNotNull:
                        if postcondition_element.get_attribute("value") != "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.InputValueEqual
                    elif postcondition_type == ConditionType.InputValueEqual:
                        if postcondition_element.get_attribute("value") == postcondition_value:
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.TextValueIsNull
                    elif postcondition_type == ConditionType.TextValueIsNull:
                        if postcondition_element.text == "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.TextValueIsNotNull
                    elif postcondition_type == ConditionType.TextValueIsNotNull:
                        if postcondition_element.text != "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.TextValueEqual
                    elif postcondition_type == ConditionType.TextValueEqual:
                        if postcondition_element.text == postcondition_value:
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                except NoSuchElementException:
                    # 找不到【后置条件元素】，不做任何的处理，直接进入下一次的循环。
                    postcondition_result = None
                finally:
                    time.sleep(loop_interval)
        
        # 判断后置条件是否满足
        if postcondition_result == False:
            if attempt < max_attempts:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件未满足，进入下一次循环！\n")
                continue
            else:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件未满足，程序已终止执行！\n")
                
            
            if terminate_on_failure:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件未满足，程序已终止执行！\n")
                exit(0)
            else:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件未满足！即将结束函数!\n")
                return None
        elif postcondition_result == None:
            rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件无法找到【验证元素】，目标元素路径: {target_xpath}\n")
        else:
            rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 后置条件已满足，目标元素路径: {target_xpath}\n")
            
        
        if preconditions_result == True and element and postcondition_result == True:
            return element
        else:
            return None






def CustomFindElement_Click(
    driver: WebDriver,
    target_xpath: str,
    step_name: str = "未命名步骤",
    precondition_xpath: str = None,
    precondition_type: ConditionType = None,
    precondition_value: str = None,
    postcondition_xpath: str = None,
    postcondition_type: ConditionType = None,
    postcondition_value: str = None,
    timeout: int = 10,
    retry_count: int = 0,
    loop_interval: float = 0.1,
    terminate_on_failure: bool = False
) -> WebElement:
    """
    执行带前置条件和后置条件验证的元素查找操作，支持自定义条件验证。
    
    该函数会在查找目标元素前后分别验证前置条件和后置条件，确保操作环境符合预期。
    支持重试机制，在超时范围内持续尝试查找元素和验证条件。
    
    Args:
        driver (WebDriver): Selenium WebDriver实例
        target_xpath (str): 目标元素的XPath表达式
        step_name (str, optional): 步骤名称，用于日志记录
        precondition_xpath (str, optional): 前置条件元素的XPath，None表示跳过验证
        precondition_type (ConditionType, optional): 前置条件类型
        precondition_value (str, optional): 前置条件所需的值（如属性值、文本值）
        postcondition_xpath (str, optional): 后置条件元素的XPath，None表示跳过验证
        postcondition_type (ConditionType, optional): 后置条件类型
        postcondition_value (str, optional): 后置条件所需的值（如属性值、文本值）
        timeout (int, optional): 单次验证的超时时间（秒）
        retry_count (int, optional): 重试次数
        loop_interval (float, optional): 重试间隔（秒）
        terminate_on_failure (bool, optional): 验证失败时是否终止程序
        
    Returns:
        WebElement: 操作成功返回目标元素，失败返回None
        
    Raises:
        None: 函数内部处理所有异常，不主动抛出
        
    Notes:
        - 当terminate_on_failure为True时，前置条件或后置条件失败会导致程序退出
        - 验证条件支持输入框值和文本内容的多种比较方式
        - 超时机制基于datetime计算，避免使用time.sleep造成的固定等待
    """
    
    attempt = 0         # 当前重试次数
    max_attempts = retry_count + 1      # 最大重试次数
    

    # 开始查找
    while attempt < max_attempts:   
        attempt += 1
        rich.print(f"[red bold]\n提示 : 当前执行 [{step_name}] 步骤，尝试次数 {attempt}/{max_attempts}")

        element : WebElement = None

        # 前置条件验证
        # print(f"\t提示 : 开始验证 [{step_name}] 前置条件 [{precondition_xpath}] ...")
        rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 前置条件 [{precondition_xpath}] ...")
        preconditions_result : bool = False
        if precondition_xpath == None or precondition_xpath == "":
            rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 前置条件验证为空,当前前置条件已满足!")
            preconditions_result = True
        else:
            rich.print(f"[green bold]\t提示 : 正在验证 [{step_name}] 前置条件验证不为空,开始进行验证 ... ")
            preconditions_verify_start_time = datetime.datetime.now()
            while preconditions_verify_start_time + datetime.timedelta(seconds=timeout) > datetime.datetime.now():
                try:
                    precondition_element = driver.find_element(by=By.XPATH,value=precondition_xpath)
                    
                    # 判断是那种验证类型
                    if precondition_type is None or precondition_type == "" or precondition_type == "":
                        preconditions_result = True
                        break
                    
                    # ConditionType.InputValueIsNull
                    elif precondition_type == ConditionType.InputValueIsNull:                        
                        if precondition_element.get_attribute("value") == "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.InputValueIsNotNull
                    elif precondition_type == ConditionType.InputValueIsNotNull:
                        if precondition_element.get_attribute("value") != "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.InputValueEqual
                    elif precondition_type == ConditionType.InputValueEqual:
                        if precondition_element.get_attribute("value") == precondition_value:
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.TextValueIsNull
                    elif precondition_type == ConditionType.TextValueIsNull:
                        if precondition_element.text == "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.TextValueIsNotNull
                    elif precondition_type == ConditionType.TextValueIsNotNull:
                        if precondition_element.text != "":
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    
                    # ConditionType.TextValueEqual
                    elif precondition_type == ConditionType.TextValueEqual:
                        if precondition_element.text == precondition_value:
                            preconditions_result = True
                            break
                        else:
                            preconditions_result = False
                            continue
                    else:
                        rich.print(f"[green bold]\t提示 : 没有匹配到条件类型!")
                    
                    
                except Exception as e:
                    # 找不到【前置条件元素】，不做任何的处理，直接进入下一次的循环。
                    preconditions_result = False
                finally:
                    time.sleep(loop_interval)
                
        
        # 判断前置条件是否满足
        if preconditions_result == False and terminate_on_failure == True:
            rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 前置条件未满足，程序已终止执行！\n")
            exit(0)
        else:
            rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 前置条件已满足，目标元素: {target_xpath}\n")
        
        
        # 查找目标元素
        rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 目标元素: {target_xpath} ...")
        if target_xpath == None or target_xpath == "":
            rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 目标元素为空,当前函数运行结束!")
            return None
        else:
            rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 正在查找目标元素: {target_xpath}")
            target_element_startfind_time = datetime.datetime.now()
            while target_element_startfind_time + datetime.timedelta(seconds=timeout) > datetime.datetime.now():
                try:
                    element = driver.find_element(By.XPATH, target_xpath)
                    # rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 找到目标元素: {target_xpath}")
                    # rich.print(f"[green bold]\t提示 : 目标元素 [{target_element}]\n")
                    break
                except:
                    # 找不到【目标元素】，不做任何的处理，直接进入下一次的循环。
                    time.sleep(loop_interval)
                    continue
                    

        if element:
            rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 目标条件已满足，目标元素路径: {target_xpath}")
            rich.print(f"[yellow bold]\t提示 : 目标元素 [{element}]\n")
        else:
            rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 未找到目标元素: {target_xpath}，程序已终止执行！\n")
            exit(0)

        

        # 后置条件验证
        rich.print(f"[green bold]\t提示 : 开始验证 [{step_name}] 后置条件 [{postcondition_xpath}] ...")
        postcondition_result : bool = None
        if postcondition_xpath == None or postcondition_xpath == "":
            rich.print(f"[green bold]\t提示 : 验证完毕 [{step_name}] 后置条件验证为空,当前前置条件已满足!")
            postcondition_result = True
        else:
            rich.print(f"[green bold]\t提示 : 正在验证 [{step_name}] 后置条件验证不为空,开始进行验证 ... ")
            preconditions_verify_start_time = datetime.datetime.now()
            while preconditions_verify_start_time + datetime.timedelta(seconds=timeout) > datetime.datetime.now():
                try:
                    postcondition_element = driver.find_element(by=By.XPATH,value=postcondition_xpath)
                    
                    # 判断是那种验证类型
                    if postcondition_type is None or postcondition_type == "" or postcondition_type == "":
                        postcondition_result = True
                        break
                    
                    # ConditionType.InputValueIsNull
                    elif postcondition_type == ConditionType.InputValueIsNull:
                        if postcondition_element.get_attribute("value") == "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.InputValueIsNotNull
                    elif postcondition_type == ConditionType.InputValueIsNotNull:
                        if postcondition_element.get_attribute("value") != "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.InputValueEqual
                    elif postcondition_type == ConditionType.InputValueEqual:
                        if postcondition_element.get_attribute("value") == postcondition_value:
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.TextValueIsNull
                    elif postcondition_type == ConditionType.TextValueIsNull:
                        if postcondition_element.text == "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.TextValueIsNotNull
                    elif postcondition_type == ConditionType.TextValueIsNotNull:
                        if postcondition_element.text != "":
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                    # ConditionType.TextValueEqual
                    elif postcondition_type == ConditionType.TextValueEqual:
                        if postcondition_element.text == postcondition_value:
                            postcondition_result = True
                            break
                        else:
                            postcondition_result = False
                            continue
                    
                except NoSuchElementException:
                    # 找不到【后置条件元素】，不做任何的处理，直接进入下一次的循环。
                    postcondition_result = None
                finally:
                    time.sleep(loop_interval)
        
        # 判断后置条件是否满足
        if postcondition_result == False:
            if terminate_on_failure:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件未满足，程序已终止执行！\n")
                exit(0)
            else:
                rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件未满足！即将结束函数!\n")
                return None
        elif postcondition_result == None:
            rich.print(f"[red bold]\t提示 : 验证完毕 [{step_name}] 后置条件无法找到【验证元素】，目标元素路径: {target_xpath}\n")
        else:
            rich.print(f"[yellow bold]\t提示 : 验证完毕 [{step_name}] 后置条件已满足，目标元素路径: {target_xpath}\n")
            
        
        if preconditions_result == True and element and postcondition_result == True:
            return element
        else:
            return None




if __name__ == "__main__":
    # 切换工作目录到当前脚本所在目录
    os.chdir(pathlib.Path(__file__).parent.absolute().resolve().__str__())
    rich.traceback.install(show_locals=True,max_frames=20,width=120)

    driver,wait,actions = Fast_Link_Debugmode_Browser()
    Goto_CurrentActivateUrl(driver=driver)
    
    element = CustomFindElement(driver=driver,
                                step_name="打开订单查询",
                                target_xpath="//*[text()='订单查询']",
                                precondition_xpath="//*[text()='发布新商品']",
                                precondition_type=ConditionType.TextValueEqual,
                                precondition_value="发布新商品",
                                terminate_on_failure=True,timeout=3,
                                postcondition_xpath="//*[text()='订单查询']",
                                postcondition_type=ConditionType.TextValueEqual,
                                postcondition_value="订单查询",
                                loop_interval=1
                                )
    if element:element.click()
    
    element = CustomFindElement(driver=driver,
                                step_name="创建新商品",
                                target_xpath="//*[text()='发布新商品']",
                                terminate_on_failure=True,timeout=3,
    )
    if element:element.click()
        
    
    